package tatrus;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * <p>Title: Display </p>
 * <p>Description: CSIS 343 Course Project</p>
 * 
 * This class is responsible for displaying the next Shape that will
 * be given, the current score of the game, and the current level of
 * the game.  It also contains the buttons that allow a player to 
 * start a new game, pause and unpause a game that is in progress,
 * exit the game completely, and to view the high scores list.  
 * 
 * @author Nick Brown
 * @email  nicholas.brown@my.uwrf.edu
 * @author John Wagner 
 * @email  john.wagner@my.uwrf.edu
 * 
 * @date November 28th 2013
 *
 */

public class Display extends JPanel 
{
	private static final long serialVersionUID = 200L;
	
	public static final int DISPLAY_WIDTH = 200;
	public static final int DISPLAY_HEIGHT = 510;
	public static final int BUTTON_WIDTH = 140;
	public static final int BUTTON_HEIGHT = 25;
	public static final int BUTTON_OFFSET = 35;
	public static final int SQUARE_SIZE = 12;
	public static final int INSET_SIZE = 60;
	public static final int DISPLAY_OFFSET = 45;
	public static final int NUMBER_OFFSET = 30;
	public static final Color BUTTON_COLOR = new Color(255,229,204);
	public static final Font BUTTON_FONT = new Font("Tahoma", Font.BOLD, 12);
	public static final Font DISPLAY_FONT = new Font("Tahoma", Font.BOLD, 14);
	
	
	private Game game;
	private JButton newGameButton, exitButton, pauseButton, highScoresButton;
	private boolean isGameRunning;

	/**
	 * Creates a new display.
	 * 
	 * @param game The Game object controlling the game
	 */
	public Display(Game game)
	{
		this.game = game;
		isGameRunning = false;
		
		/* Instantiating the "Start New Game" JButton, 
		 * registering an ActionListener using an anonymous 
		 * class, and adding the button to the GUI.  
		 */
		newGameButton = new JButton("Start New Game");
		newGameButton.setBackground(BUTTON_COLOR);
		newGameButton.setFont(BUTTON_FONT);
		newGameButton.setFocusPainted(false);
		
		newGameButton.setBounds(DISPLAY_WIDTH / 2 - BUTTON_WIDTH / 2,
								DISPLAY_HEIGHT - BUTTON_OFFSET * 4,
								BUTTON_WIDTH, BUTTON_HEIGHT);
		
		newGameButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent event)
            {
				/* Start a new game if a game 
				 * is not currently running.
				 */
				if(!isGameRunning)
				{
					isGameRunning = true;
					startNewGame();
				}
				
				else
				{
					/* Otherwise the game is running.  In this case, 
					 * if the game is not paused, the game gets paused,
					 * the pause button text is changed to "Unpause Game",
					 * and the player is asked for confirmation that they
					 * want to start a new game.
					 */
					if(!isGamePaused())
					{
						pauseButton.setText("Unpause Game");
						pauseButtonClicked();
						
						int confirmation = JOptionPane.showConfirmDialog(null,  							
								"Are you sure you want to start a new game?", 
								"Start New Game", JOptionPane.YES_NO_OPTION);
						
						/* If they confirm that they want to start a new 
						 * game, the pause button text gets changed back  
						 * to "Pause Game", and a new game is started.
						 */
						if(confirmation == 0)
						{
							pauseButton.setText("Pause Game");
							startNewGame();
						}
						
						/* If the user declines the choice to start a new
						 * game, the pause button text gets changed back 
						 * to "Pause Game" and the game resumes.
						 */
						else
						{
							pauseButton.setText("Pause Game");
							pauseButtonClicked();
						}
					}
					
					/* Otherwise, the game was paused when the player 
					 * requested a new game.  The player is asked for 
					 * confirmation on whether or not they would like to
					 * start a new game.  If they want a new game, the  
					 * pause button text is changed to "Pause Game" and 
					 * a new game is started.  If they decline, the game
					 * remains in a paused state until unpaused.
					 */
					else
					{
						int confirmation = JOptionPane.showConfirmDialog(null,   						
								"Are you sure you want to start a new game?", 
								"Start New Game", JOptionPane.YES_NO_OPTION);
						
						if(confirmation == 0)
						{
							pauseButton.setText("Pause Game");
							startNewGame();
						}
					}
				}
            }
		});
		
		add(newGameButton);
		
		/* Instantiating the "Exit Game" JButton, registering
		 * an ActionListener using an anonymous class, and 
		 * adding the button to the GUI.  
		 */
		exitButton = new JButton("Exit Game");
		exitButton.setBackground(BUTTON_COLOR);
		exitButton.setFont(BUTTON_FONT);
		exitButton.setFocusPainted(false);
		
		exitButton.setBounds(DISPLAY_WIDTH / 2 - BUTTON_WIDTH / 2,
							 DISPLAY_HEIGHT - BUTTON_OFFSET * 3,
							 BUTTON_WIDTH, BUTTON_HEIGHT);
		
		exitButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent event)
            {
				/* If the a game is currently running and not
				 * paused, the game is paused and the pause
				 * button text is set to "Unpause Game".  The
				 * player is then asked for confirmation that 
				 * they want to exit the game.
				 */
				if(!isGamePaused() && isGameRunning == true)
				{
					pauseButton.setText("Unpause Game");
					pauseButtonClicked();
					
					int confirmation = JOptionPane.showConfirmDialog(null,
							"Are you sure you want to exit the game?", 
							"Exit Game", JOptionPane.YES_NO_OPTION);
					
					/* If the player confirms that they want to exit
					 * the game, then the program terminates.
					 */
					if(confirmation == 0)
					{
						System.exit(0);
					}
					
					/* If the player declines to exit the game, the pause
					 * button text is changed to "Pause Game" and the 
					 * game resumes.  
					 */
					else
					{
						pauseButton.setText("Pause Game");
						pauseButtonClicked();
					}
				}
				
				/* Otherwise, the game was paused when the player clicked
				 * the "Exit Game" button.  The player is then asked for
				 * confirmation that they want to exit the game.  If they
				 * affirm that they want to exit the game, the program
				 * terminates.  If they decline to exit the game, the game
				 * remains in a paused state until the player unpauses it.  
				 */
				else
				{
					int confirmation = JOptionPane.showConfirmDialog(null,
							"Are you sure you want to exit the game?", 
							"Exit Game", JOptionPane.YES_NO_OPTION);
					
					if(confirmation == 0)
					{
						System.exit(0);
					}
				}
            }
		});
		
		add(exitButton);
		
		/* Instantiating the "Pause Game" JButton, registering
		 * an ActionListener using an anonymous class, and 
		 * adding the button to the GUI.  
		 */
		pauseButton = new JButton("Pause Game");
		pauseButton.setBackground(BUTTON_COLOR);
		pauseButton.setFont(BUTTON_FONT);
		pauseButton.setFocusPainted(false);
		
		pauseButton.setBounds(DISPLAY_WIDTH / 2 - BUTTON_WIDTH / 2,
							  DISPLAY_HEIGHT - BUTTON_OFFSET * 2,
							  BUTTON_WIDTH, BUTTON_HEIGHT);
		
		pauseButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent event)
            {
				/* If the game is not paused, the game enters
				 * a paused state, and the text on the button
				 * is changed to "Unpause Game".  Otherwise
				 * the game becomes unpaused, the text on the
				 * button is changed to "Pause Game", and the
				 * game resumes.
				 */
				if(!isGamePaused() && isGameRunning == true)
				{
					pauseButton.setText("Unpause Game");
					pauseButtonClicked();
				}
				else if(isGameRunning == true)
				{
					pauseButton.setText("Pause Game");
					pauseButtonClicked();
				}
            }
		});
		
		add(pauseButton);
		
		/* Instantiating the "View High Scores" JButton,
		 * registering an ActionListener using an anonymous
		 * class, and adding the button to the GUI.  
		 */
		highScoresButton = new JButton("View High Scores");
		highScoresButton.setBackground(BUTTON_COLOR);
		highScoresButton.setFont(BUTTON_FONT);
		highScoresButton.setFocusPainted(false);
		
		highScoresButton.setBounds(DISPLAY_WIDTH / 2 - BUTTON_WIDTH / 2,
								   DISPLAY_HEIGHT - BUTTON_OFFSET, 
								   BUTTON_WIDTH, BUTTON_HEIGHT);
		
		highScoresButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent event)
            {
				/* If the game is not paused, is running, and the score 
				 * manager is not open, the game enters a paused state,
				 * the text on the pause button is changed to 
				 * "Unpause Game" and the score manager is called.  
				 */
				if(!isGamePaused() && isGameRunning && !isScoreManagerOpen())
				{
					pauseButton.setText("Unpause Game");
					pauseButtonClicked();
					startScoreManager();
				}
				
				/* Otherwise if the game was already paused, 
				 * running, and the score manager is not 
				 * open, the score manager is called.
				 */
				else if(isGamePaused() && isGameRunning &&
						!isScoreManagerOpen())
				{
					startScoreManager();
				}
				
				/* Otherwise if the game is not running and the
				 * score manager is not open, the score manager
				 * is called.  
				 */
				else if(!isGameRunning && !isScoreManagerOpen())
				{
					startScoreManager();
				}
            }
		});
		
		add(highScoresButton);

		setBounds(Board.BOARD_WIDTH, 0, Display.DISPLAY_WIDTH,
				  Display.DISPLAY_HEIGHT);
		
		setLayout(null);
        setBackground(Color.BLACK);
	}
	
	/**
	 * Calls the startNewGame method of the Game class 
	 * when the "Start New Game" button is clicked.
	 */
	private void startNewGame()
	{
		game.startNewGame();
	}
	
	/**
	 * Calls the isPaused method of the game class
	 * to determine the pause state of the game.
	 * 
	 * @return true if the game is paused, otherwise false
	 */
	private boolean isGamePaused()
	{
		return game.isPaused(); 
	}
	
	/**
	 * Calls the togglePause method of the game class when
	 * the "Pause Game/Unpause Game" button is clicked.
	 */
	private void pauseButtonClicked()
	{
		game.togglePause();
	}
	
	/**
	 * Used to set the status of whether 
	 * or not a game is currently running.
	 * 
	 * @param status
	 */
	public void setGameStatus(boolean status)
	{
		isGameRunning = status;
	}
	
	/**
	 * Calls the startScoreManager method of the game class
	 * when the "View High Scores" button is clicked.
	 */
	public void startScoreManager()
	{
		game.openScoreManager();
	}
	
	/**
	 * Calls the isScoreManagerOpen method of the
	 * game class to determine whether or not an
	 * instance of the HighScoreManager class is
	 * currently active.  
	 * 
	 * @return true if a HighScoreManager instance is
	 * 		   currently active, otherwise false
	 */
	public boolean isScoreManagerOpen()
	{
		return game.isScoreManagerOpen();
	}
	
	/**
	 * Inherited method of the JPanel class.  Used to render
	 * the current game information shown on the display.
	 * 
	 * @param graphics The Graphics object used for drawing
	 */
	public void paintComponent(Graphics graphics)
	{
		super.paintComponent(graphics);
		
		graphics.setColor(Color.WHITE);
		
		graphics.setFont(DISPLAY_FONT);
		
		/* This code allows for determining the size of any particular
		 * piece of font.  This size needs to be know so that the font
		 * can be properly centered on the display.  
		 */
		BufferedImage image;
		image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
		
		FontMetrics metrics = image.getGraphics().getFontMetrics(DISPLAY_FONT);
		int stringWidth = metrics.stringWidth("Next Shape");
		
		// Positioning and drawing the "Next Shape" font on the display
		graphics.drawString("Next Shape", DISPLAY_WIDTH / 2 - stringWidth / 2,
							DISPLAY_OFFSET);
		
		stringWidth = metrics.stringWidth("Score");
		
		// Positioning and drawing the "Score" font on the display
		graphics.drawString("Score", DISPLAY_WIDTH / 2 - stringWidth / 2,
					 		DISPLAY_OFFSET * 4);
		
		String digits = String.valueOf(game.getScore());
				
		stringWidth = metrics.stringWidth(digits);
		
		// If the game is running, the current score is drawn on the display
		if(isGameRunning)
		{
			graphics.drawString(digits, DISPLAY_WIDTH / 2 - stringWidth / 2,
			 		(DISPLAY_OFFSET * 4) + NUMBER_OFFSET);
		}
		
		stringWidth = metrics.stringWidth("Level");
		
		// Positioning and drawing the "Level" font on the display
		graphics.drawString("Level", DISPLAY_WIDTH / 2 - stringWidth / 2,
					 		DISPLAY_OFFSET * 6);
		
		digits = String.valueOf(game.getLevel());
		
		stringWidth = metrics.stringWidth(digits);
		
		// If the game is running, the current level is drawn on the display
		if(isGameRunning)
		{
			graphics.drawString(digits, DISPLAY_WIDTH / 2 - stringWidth / 2,
			 		(DISPLAY_OFFSET * 6) + NUMBER_OFFSET);
		}
	
		// Drawing the "Next Shape" inset box
		graphics.drawRect(DISPLAY_WIDTH / 2 - INSET_SIZE / 2,
				  (int) (DISPLAY_OFFSET * 1.5), INSET_SIZE, INSET_SIZE);
		
		/* Getting the next Shape to be played and 
		 * drawing it on the display as long as the game
		 * is running and the reference is not null. 
		 */
		Shape nextShape = game.getNextShape();
		
		if(nextShape != null && isGameRunning)
		{
			graphics.setColor(nextShape.getColor());
			int[][] shapeGrid = nextShape.getShapeGrid(0);
			int columns = nextShape.getColumns();
            int rows = nextShape.getRows();
            int gridSize = nextShape.getShapeGridSize();
     
            int initialX = ((DISPLAY_WIDTH / 2) - (columns * SQUARE_SIZE / 2));
            int initialY = (((int) (DISPLAY_OFFSET * 1.5) + INSET_SIZE / 2) -
            					   (rows * SQUARE_SIZE / 2));
     
            int upperOffset = nextShape.getUpperOffset(0);
			
			int columnIndex = 0, rowIndex = 0;  
			
			for(int i = 0; i < gridSize; i++)
			{
				for(int j = 0; j < gridSize; j++)
				{
					if(shapeGrid[i][j] == 1)
					{
					  graphics.fillRect(initialX + (columnIndex * SQUARE_SIZE),
										initialY + (rowIndex * SQUARE_SIZE) - 
										(upperOffset * SQUARE_SIZE),
										SQUARE_SIZE, SQUARE_SIZE);
					}
					
					columnIndex++;
				}
				
				columnIndex = 0;
				rowIndex++;
			}
		}
	}
}